package com.timebank.score.listener;

import com.alibaba.fastjson2.JSON;
import com.rabbitmq.client.Channel;
import com.timebank.common.core.constant.SecurityConstants;
import com.timebank.common.core.constant.TimeCoinTradeStatusConstant;
import com.timebank.common.core.constant.message.MessageTypeConstant;
import com.timebank.common.core.constant.rabbitmq.queue.QueueConstant;
import com.timebank.common.core.exception.ServiceException;
import com.timebank.common.core.result.Result;
import com.timebank.common.core.web.pojo.AjaxResult;
import com.timebank.score.mapper.PrizeMapper;
import com.timebank.score.pojo.entity.Prize;
import com.timebank.score.pojo.entity.PrizeMessage;
import com.timebank.system.pojo.SysUser;
import com.timebank.system.service.RemoteUserService;
import com.timebank.timecoin.pojo.entity.TimeCoinTrade;
import com.timebank.timecoin.pojo.entity.User;
import com.timebank.timecoin.service.RemoteContractService;
import com.timebank.timecoin.service.RemoteTimeCoinService;
import com.timebank.websocket.pojo.vo.SendMsgVO;
import com.timebank.websocket.service.RemoteWebSocketService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.io.IOException;
import java.rmi.ServerException;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;

/**
 * 奖品消息 监听类
 * @author shiliuyinzhen
 */
@Component
@Slf4j
public class PrizeMessageListener {

    @Resource
    private PrizeMapper prizeMapper;
    @Resource
    private RemoteWebSocketService remoteWebSocketService;

    @Resource
    private RemoteUserService remoteUserService;

    @Resource
    private RemoteContractService remoteContractService;

    @Resource
    private RemoteTimeCoinService remoteTimeCoinService;

    /**
     * 处理 奖品 服务消息
     *
     * @param msg
     * @param message
     * @param channel
     * @throws IOException
     */
    @RabbitListener(queues = QueueConstant.PRIZE_MESSAGE_QUEUE)
    @RabbitHandler
    public void HandelVolunteerServiceMessage(String msg, Message message, Channel channel) throws IOException {
        //将json格式字符串转换为对象
        PrizeMessage prizeMessage = JSON.parseObject(msg, PrizeMessage.class);
        log.info("接收到奖品消息：{}", prizeMessage);
        Integer typeId = prizeMessage.getTypeId();
        //如果是时间币奖品
        if (typeId.equals(MessageTypeConstant.SCORE_PRIZE_GET_TIMECOIN)){
            //获取用户信息
            List<Long> userIds  = new ArrayList<>();
            userIds.add(prizeMessage.getGetterId());
            Result<List<SysUser>> result =
                    remoteUserService.getUserByIds(userIds, SecurityConstants.INNER);
            if (result.getData() == null) {
                throw new ServiceException("查询用户信息失败");
            }
            List<SysUser> sysUsers = result.getData();
            if (sysUsers.size() == 0){
                throw new ServiceException("查询用户信息失败");
            }
            SysUser sysUser = sysUsers.get(0);
            //查询奖品信息
            Prize prizeDTO = Prize.builder()
                    .id(prizeMessage.getPrizeId())
                    .build();
            Prize prize = prizeMapper.getPrize(prizeDTO);
            if (prize == null){
                throw new ServerException("查询奖品失败，奖品id:" + prize.getId());
            }
            //设置时间币
            sysUser.setTimeCoin(sysUser.getTimeCoin() + prize.getTimeCoin());
            //更新数据库
            Result<Boolean> res =
                    remoteUserService.updateUserLoginInfo(sysUser, SecurityConstants.INNER);
            if (res.getData() == null || res.getData() == false){
                throw new ServiceException("更新用户时间币失败");
            }
            //更新fabric账本
            User user = User.builder()
                    .userId(sysUser.getUserId())
                    .userName(sysUser.getUserName())
                    .timeCoin(sysUser.getTimeCoin())
                    .build();
            AjaxResult ajaxResult =
                    remoteContractService.updateContractUser(user,SecurityConstants.INNER);
            if (ajaxResult.isError()){
                throw new ServerException("更新fabric账本失败");
            }
            //创建时间币交易
            TimeCoinTrade timeCoinTrade = TimeCoinTrade.builder()
                    .payerId(999L)
                    .payerName("system")
                    .getterId(sysUser.getUserId())
                    .getterName(sysUser.getUserName())
                    .timeCoin(prize.getTimeCoin())
                    .tradeTime(LocalDateTime.now())
                    .status(TimeCoinTradeStatusConstant.PAID)
                    .build();
            timeCoinTrade.setCreateBy("system");
            timeCoinTrade.setCreateTime(LocalDateTime.now());
            timeCoinTrade.setRemark("积分抽奖获得时间币");
            ajaxResult = remoteTimeCoinService.createTrade(timeCoinTrade,SecurityConstants.INNER);
            if (ajaxResult.isError()){
                throw new ServiceException("创建积分抽奖获得时间币交易失败");
            }
            //发送时间币到账消息
            SendMsgVO sendMsgVO = SendMsgVO.builder()
                    .senderId("999")
                    .senderName("system")
                    .getterId(sysUser.getUserId().toString())
                    .timeCoin(prize.getTimeCoin())
                    .title("积分抽奖奖品到账")
                    .content("积分抽奖获得时间币：" + prize.getTimeCoin())
                    .typeId(MessageTypeConstant.SCORE_PRIZE_GET_TIMECOIN)
                    .build();
            ajaxResult = remoteWebSocketService.sendMessage(sendMsgVO,SecurityConstants.INNER);
            if (ajaxResult.isError()){
                throw new ServerException("发送时间币到账消息失败");
            }
        } else if (typeId.equals(MessageTypeConstant.SCORE_PRIZE_GET_SCORE)) {
            //如果是积分奖品
        }else {
            throw new ServerException("未知奖品类型");
        }
        try {
            // RabbitMQ的ack机制中，第二个参数返回true，表示需要将这条消息投递给其他的消费者重新消费
            channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
        } catch (Exception e) {
            // 第三个参数true，表示这个消息会重新进入队列
            //channel.basicNack(deliveryTag, false, true);
            channel.basicReject(message.getMessageProperties().getDeliveryTag(), true);
        }

    }

}
